﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LogicExpressionCalculator
{
    public class ExpressionCalculator
    {
        /// <summary>
        /// Calculate the expression list
        /// </summary>
        /// <param name="expression">
        /// Input is a Stack with value type: bool & LogicOperatorType.
        /// And the expression must be calculatable.</param>
        /// <returns></returns>
        public static bool LogicCalculate(Stack<object> expression)
        {
            Stack<bool> tmpStack = new Stack<bool>();
            if (expression.Count == 0)
            {
                throw new Exception("No object in logic expression.");
            }
            while (expression.Count > 0)
            {
                object tmpObj = expression.Pop();
                if (tmpObj is bool)
                {
                    tmpStack.Push((bool)tmpObj);
                }
                else if (tmpObj is LogicOperatorType)
                {
                    LogicOperatorType type = (LogicOperatorType)tmpObj;
                    switch (type)
                    {
                        case LogicOperatorType.Negation:
                            {
                                bool operand1 = tmpStack.Pop();
                                tmpStack.Push(oneOperatorCalculate(operand1));
                                break;
                            }
                        case LogicOperatorType.Conjunction:
                        case LogicOperatorType.Disjunction:
                        case LogicOperatorType.Implication:
                        case LogicOperatorType.Biconditional:
                            {
                                bool operand1 = tmpStack.Pop();
                                bool operand2 = tmpStack.Pop();
                                tmpStack.Push(twoOperatorCalculate(operand1
                                    , operand2, type));
                                break;
                            }
                    }
                }
                else
                {
                    throw new Exception("Logic Expression Error.");
                }
            }
            if (tmpStack.Count != 1)
            {
                throw new Exception("Logic Expression Error");
            }
            return tmpStack.Pop();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        private static bool oneOperatorCalculate(bool operand)
        {
            return !operand;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        private static bool twoOperatorCalculate(bool operand1, bool operand2
            , LogicOperatorType type)
        {
            switch (type)
            {
                case LogicOperatorType.Conjunction:
                    {
                        return operand1 && operand2;
                    }
                case LogicOperatorType.Disjunction:
                    {
                        return operand1 || operand2;
                    }
                case LogicOperatorType.Implication:
                    {
                        return !(operand1 == true && operand2 == false);
                    }
                case LogicOperatorType.Biconditional:
                    {
                        return operand1 == operand2;
                    }
            }
            throw new Exception("Calculation Error");
        }
    }
}
